const canvas = document.querySelector('canvas')
const ctx = canvas.getContext('2d', {
  willReadFrequently: true
})

function init() {
  const img = new Image()
  img.src = './test.png'
  img.onload = () => {
    canvas.width = img.width / 2
    canvas.height = img.height / 2
    ctx.drawImage(img, 0, 0, canvas.width, canvas.height)
  }
}

init()

function point2Index(x, y) {
  return (x + y * canvas.width) * 4
}

function getPiointColor(x, y, imgData) {
  const index = point2Index(x, y)
  return [
    imgData.data[index],
    imgData.data[index + 1],
    imgData.data[index + 2],
    imgData.data[index + 3]
  ]
}

function diff(color1, color2) {
  return Math.abs(color1[0] - color2[0]) +
    Math.abs(color1[1] - color2[1]) +
    Math.abs(color1[2] - color2[2]) +
    Math.abs(color1[3] - color2[3])
}

canvas.addEventListener('click', (e) => {
  const x = e.offsetX
  const y = e.offsetY

  const imgData = ctx.getImageData(0, 0, canvas.width, canvas.height)
  const clickColor = getPiointColor(x, y, imgData)
  const greenColor = [0, 255, 0, 255]

  // 图片过大时，递归栈溢出，使用循环代替递归
  // function _changePointColor(x, y) {
  //   if (x < 0 || x >= canvas.width || y < 0 || y >= canvas.height) {
  //     return
  //   }
  //   const color = getPiointColor(x, y, imgData)
  //   if (diff(color, clickColor) > 100) {
  //     return
  //   }
  //   if (diff(color, greenColor) === 0) {
  //     return
  //   }
  //   const index = point2Index(x, y)
  //   imgData.data.set(greenColor, index)
  //   _changePointColor(x + 1, y)
  //   _changePointColor(x - 1, y)
  //   _changePointColor(x, y + 1)
  //   _changePointColor(x, y - 1)
  // }
  // _changePointColor(x, y)

  function _changePointColor(x, y) {
    if (x < 0 || x >= canvas.width || y < 0 || y >= canvas.height) {
      return
    }

    const stack = [[x, y]]

    while (stack.length > 0) {
      const [currentX, currentY] = stack.pop()

      // 检查边界
      if (currentX < 0 || currentX >= canvas.width || currentY < 0 || currentY >= canvas.height) {
        continue
      }

      const color = getPiointColor(currentX, currentY, imgData)

      // 检查颜色差异和是否已经是目标颜色
      if (diff(color, clickColor) > 300 || diff(color, greenColor) === 0) {
        continue
      }

      // 设置新颜色
      const index = point2Index(currentX, currentY)
      imgData.data.set(greenColor, index)

      // 将相邻点加入栈中
      stack.push([currentX + 1, currentY])
      stack.push([currentX - 1, currentY])
      stack.push([currentX, currentY + 1])
      stack.push([currentX, currentY - 1])
    }
  }
  _changePointColor(x, y)

  ctx.putImageData(imgData, 0, 0)
})